package Main;

import java.io.*;
import java.util.Enumeration;
import java.util.Vector;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;

class Bluetooth implements CommandListener, DiscoveryListener {
    OutputStream os;
    InputStream is; 

    LocalDevice localDev;
    DiscoveryAgent discAgent;
    Vector devices, unaddedDevices, services;
    RemoteDevice remDevice;

//    StringItem stringItem;
    int devicesFound = 0;
    String[] namesArr, addressArr;

    List serversList;
    javax.microedition.lcdui.Command cancelCommand, selectCommand;
    Displayable oldScreen;

    Thread readThread;

//    final UUID uuid = new UUID(0xABCDEF);
    final UUID uuid = new UUID("3B9FA89520078C303355AAA694238F08", false); 

    final int readLength = 10;
    private boolean inquiryActive;
    private StreamConnection sc;
    /*
    * Initiate bluetooth stack
     * returns null if initiates successfully, otherwise an error message
    */
   public void InitBluetooth()
   {
       try
       {
           if(localDev == null)
           {
               localDev = LocalDevice.getLocalDevice();
               localDev.setDiscoverable(DiscoveryAgent.GIAC);
               discAgent = localDev.getDiscoveryAgent();
           }
//           stringItem.setText("Bluetooth initialized");
       }
       catch(Exception b)
       {
           Main.PowerPongMIDlet.showAlert("Bluetooth", "Could not init bluetooth stack.", 500);
//           stringItem.setText("Cannot init bluetooth stack. ");
       }
   }

   public boolean IsConnected()
   {
       return this.os != null;
   }
   
   // host a server over the bluetooth
   StreamConnection connection;
   StreamConnectionNotifier notifier;
   Thread serverThread;
   public void CreateServer()
   {
       serverThread = new Thread()
       {
           public void run()
           {
                try {
                    String conString = "btspp://localhost:" + uuid + ";name=PPS"; // authenticate=false;encrypt=false;

        //            stringItem.setText(conString);
//                    Main.PowerPongMIDlet.showAlert("Bluetooth", "Server created... Waiting for clients.", 500);

                    localDev.setDiscoverable(DiscoveryAgent.GIAC);
        //                this.stringItem.setText("Bluetooth server created");
                    notifier = (StreamConnectionNotifier) Connector.open(conString, Connector.READ_WRITE);
                    // stringItem.setText(notifier.toString());
        //            stringItem.setText(serv.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false));

                    Main.PowerPongMIDlet.setMode(Main.PowerPongMIDlet.SERVER);
                    connection = notifier.acceptAndOpen();
                    os = connection.openOutputStream();
                    is = connection.openInputStream();

                    readThread = ReadThread();
                    readThread.start();

                    Main.PowerPongMIDlet.showDisplayable(Main.PowerPongMIDlet.gfx);
                    Main.PowerPongMIDlet.acc.EnableAccelerometer();
                    Main.PowerPongMIDlet.bt.SendString("BY" + Main.PowerPongMIDlet.gfx.getBall().getY());  // synchronize ball position with client for first game
                    SendString("start");
                } catch (IOException ex) {
                    Main.PowerPongMIDlet.showAlert("Bluetooth", "Could not create server", 500);
                }
           }
       };
       serverThread.start();
   }

   // Close bluetooth connection
   public void close()
   {
    try {
        os.flush();
        os.close();
        is.close();
    } catch (IOException ex) {
        Main.PowerPongMIDlet.showAlert("Bluetooth", "Close bluetooth failed", 500);
    }
   }

   //<editor-fold defaultstate="collapsed" desc="Create Read thread: reads from bluetooth">
   private Thread ReadThread()
   {
       return new Thread()
               {
                   public void run()
                   {
                       String readString = "";
                           
                       try {
                           byte[] byte_arr = new byte[readLength];
                           int r = 0;
                           while(!readString.startsWith("stop"))
                           {
                               r = is.read(byte_arr, 0, readLength);
                               readString = new String(byte_arr, 0, readLength);
                               if(readString.startsWith("paint"))
                                    Main.PowerPongMIDlet.gfx.repaint();
                               else if(readString.startsWith("start")) // server sends start
                               {
                                   Main.PowerPongMIDlet.bt.SendString("okay");
                                   Main.PowerPongMIDlet.showDisplayable(Main.PowerPongMIDlet.gfx);
                                   Main.PowerPongMIDlet.acc.EnableAccelerometer();
                                   Main.PowerPongMIDlet.startGameThread();
                               }
                               else if(readString.startsWith("restart")) // server sends start
                               {
                                   Main.PowerPongMIDlet.gfx.resetGame();
                               }
                               else if(readString.startsWith("okay")) // then client replies with okay
                                   Main.PowerPongMIDlet.startGameThread();
                               else if(readString.startsWith("stop"))
                                   break;
                               else
                               {
                                   String prefix = readString.substring(0, 2);
                                   double num = Double.parseDouble(readString.substring(2));
                                   if(r != -1)
                                   {
    //                                   System.out.println("read: (" + r + ") " + readString);
                                       if(prefix.equals("C "))
                                       {
                                           Main.PowerPongMIDlet.gfx.setClientAccData(num);
    //                                       Main.PowerPongMIDlet.gfx.setTitle("CLIENT DATA RECEIVED");
                                       }
                                       else if(prefix.equals("P "))
                                           Main.PowerPongMIDlet.gfx.GetPlayer().setY(num);
                                       else if(prefix.equals("S1"))
                                       {
                                           Main.PowerPongMIDlet.gfx.GetOpponent().setScore((int) (num)); 
                                       }
                                       else if(prefix.equals("S2"))
                                       {
                                           Main.PowerPongMIDlet.gfx.GetPlayer().setScore((int) (num)); 
                                       }
                                       else if(prefix.equals("S "))
                                           Main.PowerPongMIDlet.gfx.setServerAccData(num);
//                                           Main.PowerPongMIDlet.gfx.setOpponentPosition(num);
                                       else if(prefix.equals("BX"))
                                           Main.PowerPongMIDlet.gfx.setBallPositionX(1 - num);
                                       else if(prefix.equals("BY"))
                                       {
                                           Main.PowerPongMIDlet.gfx.setTitle(readString);
                                           Main.PowerPongMIDlet.gfx.setBallPositionY(num);
                                       }
                                       else if(prefix.equals("VY"))
                                           Main.PowerPongMIDlet.gfx.setBallVelocityY(num);
//                                       else if(prefix.charAt(0) == 'C')
//                                       {
//                                           if(prefix.charAt(1) == 'R')
//                                           {
//                                               
//                                           }
//                                       }
                                       else if(prefix.equals("W "))
                                       {
                                           Main.PowerPongMIDlet.gfx.forcedGenerate(Character.digit(readString.charAt(2), 10), readString.charAt(3) == '1', Double.parseDouble(readString.substring(4)));
                                           if(Character.digit(readString.charAt(2), 10) == 1)
                                               Main.PowerPongMIDlet.gfx.opponent.decAmmo();
                                           
                                       }

    //                                   else if(readString.startsWith("P"))
    //                                   {
    //                                       Main.PowerPongMIDlet.showDisplayable(Main.PowerPongMIDlet.gfx);
    //                                       Main.PowerPongMIDlet.gfx.setOpponentPosition(Double.parseDouble(readString.substring(1)));
    //                                   }
                                   }   
                               }
                               //                            stringItem.setText("read: " + readString);
                               byte_arr = new byte[readLength];
                           }
                           Main.PowerPongMIDlet.stopGameThread();                           
                           
                           if(is != null)
                                is.close();
                           if(sc != null)
                                sc.close();
                           
                           Main.PowerPongMIDlet.showDisplayable(Main.PowerPongMIDlet.menu);
                           readThread = null;
                           // int b = is.read();
                       } catch (IOException ex) {
                           //                        serversList.setTitle(ex.getMessage());
                           System.out.println(ex.getMessage());
                           Main.PowerPongMIDlet.showDisplayable(Main.PowerPongMIDlet.getMainForm());
                           Main.PowerPongMIDlet.getMainForm().setTitle("io  err: " + ex.getMessage());
                       } catch (NumberFormatException ex) {
//                                                   serversList.setTitle(ex.getMessage());
                           Main.PowerPongMIDlet.gfx.setTitle("invalid message");
                           Main.PowerPongMIDlet.showDisplayable(Main.PowerPongMIDlet.getMainForm());
                           Main.PowerPongMIDlet.getMainForm().setTitle("num err: '" + readString.substring(2) + "'");
                       }
                   }
               };

   }
   //</editor-fold>

   public void SendString(String dataString)
   {
        while(dataString.length() < readLength) { dataString = dataString + "0"; }
        if(dataString.length() > readLength) dataString = dataString.substring(0, readLength);
        try {
            if(os != null)
            {
                os.write(dataString.getBytes());
                os.flush();
            }
        } catch (IOException ex) {
        }
   }

   // be a client and look for a bluetooth server
   public void FindServer(String serverName)
   {
       if(serverName == null)
       {
           if(devices == null)
               devices = new Vector();
           else if(!devices.isEmpty())
               devices.removeAllElements();

           if(services == null)
               services = new Vector();
           
           devicesFound = 0;
           
           if(unaddedDevices == null)
               unaddedDevices = new Vector();

           try
           {
               discAgent.startInquiry(DiscoveryAgent.GIAC, this);
               inquiryActive = true;

               Image[] img = null;
               serversList = new List("Choose server", Choice.EXCLUSIVE);//, namesArr, img);
               serversList.addCommand(getCancelCommand());
               serversList.addCommand(getSelectCommand());
               serversList.setCommandListener(this);
               Main.PowerPongMIDlet.showDisplayable(serversList);
           }
           catch(Exception e)
           {
               Main.PowerPongMIDlet.menu.setTitle("Error finding server");
           }
       }
   }

   // found server on bluetooth
    public void deviceDiscovered(RemoteDevice rd, DeviceClass dc) {
        try
        {
            if(devices.indexOf(rd) == -1)
            {
                devicesFound++;
//                servers.setText(devicesFound + " device(s) discovered");
                serversList.setTitle("Choose server (" + devicesFound + ")");

                devices.addElement(rd);
                serversList.append(rd.getFriendlyName(false), null);
            }
        }
        catch(Exception c)
        {
            unaddedDevices.addElement(rd);
        }

    }

    // done searching for bluetooth devices
    public void inquiryCompleted(int i) {
        inquiryActive = false;
//        stringItem.setLabel("Inquiry completed: " + devicesFound);

        namesArr = new String[devices.size()];
        addressArr = new String[devices.size()];

        for(int y = 0 ; y < unaddedDevices.size() ; y++)
        {
            try
            {
                serversList.append(((RemoteDevice) unaddedDevices.elementAt(y)).getFriendlyName(true), null);
            }
            catch (IOException ex)
            {
            }
        }
        
        if(serversList.size() == 0 )
        {
            Main.PowerPongMIDlet.showAlert("Servers", "No servers found.", 1500);
            Main.PowerPongMIDlet.showDisplayable(Main.PowerPongMIDlet.menu);
        }
//            Main.PowerPongMIDlet.revertDisplayable();
    }

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: getCancelCommand ">
    /**
     * Returns an initialized instance of cancelCommand component.
     * @return the initialized component instance
     */
    public Command getCancelCommand() {
       if (cancelCommand == null) {
            // write pre-init user code here
          cancelCommand = new Command("Cancel", Command.CANCEL, 0);
            // write post-init user code here
       }
       return cancelCommand;
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc=" Generated Getter: getSelectCommand ">
    /**
     * Returns an initialized instance of selectCommand component.
     * @return the initialized component instance
     */
    public Command getSelectCommand () {
       if (selectCommand == null) {
            // write pre-init user code here
          selectCommand = new Command("Select", Command.OK, 0);
            // write post-init user code here
       }
       return selectCommand;
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Unused bluetooth functions">
    public void serviceSearchCompleted(int i, int i1) {
//        serversList.append("Service search completed", null);
//        for (int a = 0; a < services.size() ; a++)
//        {
//            ServiceRecord rec = (ServiceRecord) services.elementAt(i);
//            DataElement e = rec.getAttributeValue(0x0001); // ServiceClassIDList
//            Enumeration en = (Enumeration) e.getValue();
//            DataElement e2 = (DataElement) en.nextElement();
//            Object v = e2.getValue();
//            serversList.append(v.toString(), null);
//        }
//        serversList.append("Done with services", null);
        byte[] bytes = new byte[readLength];
        
        if(services.size() == 0)
        {
            Main.PowerPongMIDlet.showAlert("Servers", "No servers found.", 1500);
            return;
        }
//        int b = serversList.getSelectedIndex() - devices.size();
        try {
            sc = (StreamConnection) Connector.open(services.elementAt(0).toString());
            is = sc.openInputStream();
            os = sc.openOutputStream();

            Main.PowerPongMIDlet.showDisplayable(Main.PowerPongMIDlet.gfx);
            readThread = ReadThread();
            readThread.start();

            devices.removeAllElements();
            unaddedDevices.removeAllElements();
            services.removeAllElements();
            
            Main.PowerPongMIDlet.setMode(Main.PowerPongMIDlet.CLIENT); 
            
//            Main.PowerPongMIDlet.acc.EnableAccelerometer();
            
//            Main.PowerPongMIDlet.startGameThread();
        } catch (Exception ex) {
            serversList.append("ex: " +  ex.getMessage(), null);
        }
//        stringItem.setText("Service search completed");
    }

    public void servicesDiscovered(int i, ServiceRecord[] srs) {
        for(int a = 0 ; a < srs.length ; a++)
        {
            ServiceRecord sv = srs[a];
            String url = sv.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
            services.addElement(url);
        }
    }
    //</editor-fold>

    
//    boolean serviceSearch = false;
    //<editor-fold defaultstate="collapsed" desc=" Generated Method: commandAction for Displayables ">
    /**
     * Called by a system to indicated that a command has been invoked on a particular displayable.
     * @param command the Command that was invoked
     * @param displayable the Displayable where the command was invoked
     */
    public void commandAction(Command command, Displayable displayable) {
       // write pre-action user code here
        if (displayable == serversList) 
        {
            if (command == cancelCommand) {
                devices.removeAllElements();
                unaddedDevices.removeAllElements();
                services.removeAllElements();
                Main.PowerPongMIDlet.showDisplayable(Main.PowerPongMIDlet.menu);
//                Main.PowerPongMIDlet.revertDisplayable();
            }
            else if (command == selectCommand)
            {
//                if(serviceSearch)
//                {
//                    
//            //        }
//                }
//                else {
                if(inquiryActive)
                {
                    discAgent.cancelInquiry(this);
                }
                if(serversList.getSelectedIndex() > -1)
                {
                    String selIndex = serversList.getString(serversList.getSelectedIndex());
                    serversList.setTitle("Selected: " + selIndex);
                    remDevice = (RemoteDevice) devices.elementAt(serversList.getSelectedIndex());

                    String conString = null;
                    int d = 0;
                    try
                    {
                        UUID[] searchUUID = {uuid}; // only look for rfcomm
                        discAgent.searchServices(null, searchUUID, remDevice, this);
                    }
                    catch (Exception ex) {
                        String err = ex.getMessage();
                            serversList.append(Integer.toString(d), null);
                        for (int x = 0 ; x < err.length() / 10; x++)
                        {
                            serversList.append(err.substring(x*10, (x+1)*10), null);
                        }
                        serversList.append(err.substring(err.length() - 10, err.length()), null);
                    }
                } // }
            }
        }
       // write post-action user code here
    }
    //</editor-fold>

}
